package com.LachesismStorm.lachesism.core.exception;

import com.LachesismStorm.lachesism.core.common.response.ResponseResult;
import com.LachesismStorm.lachesism.core.exception.mapper.ExceptionLogMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

/**
 * 全局异常处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private ExceptionLogMapper exceptionLogMapper;  // 注入 ExceptionLogMapper

    @Autowired
    private HttpServletRequest request; // 注入 HttpServletRequest

    @ResponseBody
    @ExceptionHandler(value = ApiException.class)
    public ResponseResult handle(ApiException e) {
        // 记录异常日志
        recordExceptionLog(e);

        if (e.getErrorCode() != null) {
            return ResponseResult.failed(e.getErrorCode());
        }
        return ResponseResult.failed(e.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseResult handleValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = null;
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                message = fieldError.getField() + fieldError.getDefaultMessage();
            }
        }

        // 记录异常日志
        recordExceptionLog(e);

        return ResponseResult.validateFailed(message);
    }

    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public ResponseResult handleValidException(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = null;
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                message = fieldError.getField() + fieldError.getDefaultMessage();
            }
        }

        // 记录异常日志
        recordExceptionLog(e);

        return ResponseResult.validateFailed(message);
    }

    @ResponseBody
    @ExceptionHandler(value = RuntimeException.class)
    public ResponseResult handleRuntimeException(RuntimeException e) {
        e.printStackTrace();

        // 记录异常日志
        recordExceptionLog(e);

        return ResponseResult.failed("系统异常");
    }

    // 记录异常日志的方法
    private void recordExceptionLog(Exception e) {
        // 构造日志对象
        ExceptionLog exceptionLog = new ExceptionLog();

        // 设置异常消息，确保不为空
        String exceptionMessage = e.getMessage();
        if (exceptionMessage == null) {
            exceptionMessage = e.toString(); // 获取异常的类名 + 错误信息
        }
        exceptionLog.setExceptionMessage(exceptionMessage);

        // 设置堆栈信息
        exceptionLog.setStackTrace(getStackTrace(e));

        // 获取请求 URI、方法和 User-Agent
        exceptionLog.setRequestUri(request.getRequestURI() != null ? request.getRequestURI() : "未知");
        exceptionLog.setMethod(request.getMethod() != null ? request.getMethod() : "未知");
        exceptionLog.setUserAgent(request.getHeader("User-Agent") != null ? request.getHeader("User-Agent") : "未知");

        // 设置当前时间戳和方法名称
        exceptionLog.setTimestamp(LocalDateTime.now());
        exceptionLog.setMethodName(e.getStackTrace().length > 0 ? e.getStackTrace()[0].getMethodName() : "未知");

        // 插入数据库
        exceptionLogMapper.insertExceptionLog(exceptionLog);
    }

    // 获取堆栈信息的方法
    private String getStackTrace(Exception e) {
        StringBuilder stackTrace = new StringBuilder();
        for (StackTraceElement element : e.getStackTrace()) {
            stackTrace.append(element.toString()).append("\n");
        }
        return stackTrace.length() > 0 ? stackTrace.toString() : "堆栈信息为空";
    }
}
